package q.yazg;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 *
 * @author khalisq
 */
public final class Constants {
        
    private static final String CONSTANTS_FILE = "props.json";
    private static final JSONObject OBJ = init();
    private static final boolean LOG_UNFOUND = getBooleanInt("debug.unfoundPropLog", false);
    
    private static JSONObject init(){
        try {
            FileInputStream fin= new FileInputStream(CONSTANTS_FILE);
            byte[] bytes = new byte[fin.available()];
            fin.read(bytes);
            return new JSONObject(new String(bytes));
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
        
    public static boolean getBoolean(String path) throws JSONException{
        Object o = new Path().parse(path).get(OBJ);
        if(!(o instanceof Boolean))throw new JSONException(path + " is not a boolean!");
        return (Boolean) o;
    }
    
    public static boolean getBoolean(String path, boolean d){
        try {
            return getBoolean(path);
        } catch (JSONException ex) {
            if(LOG_UNFOUND)System.err.println(path+" not found, assigning value "+d);
            return d;
        }
    }
    
    private static boolean getBooleanInt(String path, boolean d){
        try {
            return getBoolean(path);
        } catch (JSONException ex) {
            return d;
        }
    }
    
    public static String getString(String path) throws JSONException{
        Object o = new Path().parse(path).get(OBJ);
        if(!(o instanceof String))throw new JSONException(path + " is not a string!");
        return (String) o;
    }
    
    public static String getString(String path, String d){
        try {
            return getString(path);
        } catch (JSONException ex) {
            if(LOG_UNFOUND)System.err.println(path+" not found, assigning value "+d);
            return d;
        }
    }
    
    public static double getDouble(String path) throws JSONException{
        Object o = new Path().parse(path).get(OBJ);
        if(!(o instanceof Double))throw new JSONException(path + " is not a double!");
        return (Double) o;
    }
    
    public static double getDouble(String path, double d){
        try {
            return getDouble(path);
        } catch (JSONException ex) {
            if(LOG_UNFOUND)System.err.println(path+" not found, assigning value "+d);
            return d;
        }
    }
    
    public static float getFloat(String path) throws JSONException{
        Object o = new Path().parse(path).get(OBJ);
        if(o instanceof Double){
            return ((Double)o).floatValue();
        }
        if(!(o instanceof Float))throw new JSONException(path + " is not a float!");
        return (Float) o;
    }
    
    public static float getFloat(String path, float d){
        try {
            return getFloat(path);
        } catch (JSONException ex) {
            if(LOG_UNFOUND)System.err.println(path+" not found, assigning value "+d);
            return d;
        }
    }
    
    public static int getInt(String path) throws JSONException{
        Object o = new Path().parse(path).get(OBJ);
        if(!(o instanceof Integer))throw new JSONException(path + " is not an integer!");
        return (Integer) o;
    }
    
    public static int getInt(String path, int d){
        try {
            return getInt(path);
        } catch (JSONException ex) {
            if(LOG_UNFOUND)System.err.println(path+" not found, assigning value "+d);
            return d;
        }
    }
    
    public static long getLong(String path) throws JSONException{
        Object o = new Path().parse(path).get(OBJ);
        if(!(o instanceof Long))throw new JSONException(path + " is not a long!");
        return (Long) o;
    }
    
    public static long getLong(String path, long d){
        try {
            return getLong(path);
        } catch (JSONException ex) {
            if(LOG_UNFOUND)System.err.println(path+" not found, assigning value "+d);
            return d;
        }
    }
    
    private static class Path{
        
        private Component[] val;
        
        private abstract class Component{
            abstract Object getChild(Object parent) throws JSONException;
        }
        
        private class Key extends Component{
            
            String key;

            public Key(String key) {
                this.key = key;
            }
            
            @Override
            Object getChild(Object parent) throws JSONException{
                if(!(parent instanceof JSONObject))return null;
                return ((JSONObject)parent).get(key);
            }
            
        }
        
        private class Index extends Component {

            int index;

            public Index(int index) {
                this.index = index;
            }
            
            Object getChild(Object parent) throws JSONException {
                if(!(parent instanceof JSONArray))return null;
                return ((JSONArray)parent).get(index);
            }
        }
    
        Path parse(String str){
            List<Component> ret = new ArrayList();
            StringBuilder sb = new StringBuilder();
            for(int i = 0;i<str.length();i++){
                char c = str.charAt(i);
                if(c=='.'){
                    if(sb.length()!=0){
                        ret.add(new Key(sb.toString()));
                        sb.delete(0, sb.length());
                    }
                } else if(c=='[') {
                    i++;
                    if(sb.length()!=0){
                        ret.add(new Key(sb.toString()));
                        sb.delete(0, sb.length());
                    }                    
                    for(c=str.charAt(i);c!=']';i++,c=str.charAt(i)){
                        sb.append(c);
                    }
                    ret.add(new Index(Integer.parseInt(sb.toString())));
                    sb.delete(0, sb.length());
                } else {
                    sb.append(c);
                }
            }
            if(sb.length()!=0){
                ret.add(new Key(sb.toString()));
                sb.delete(0, sb.length());
            }
            val=ret.toArray(new Component[ret.size()]);
            return this;
        }
        
        Object get(Object root) throws JSONException{
            for(Component c:val){
                root=c.getChild(root);
            }
            return root;
        }
    }
    
}
